#include <QMessageBox>
#include <QKeyEvent>
#include "../../includes/NeonCore/NeonWidget.hpp"
using namespace Neon;

NeonWidget::NeonWidget(const QString &title, nint32 interval, QWidget *parent)
	: QGLWidget(parent)
{
	setWindowTitle(title);

	m_sceneTimer = new QTimer(this);
	connect(m_sceneTimer, SIGNAL(timeout()), this, SLOT(timedOut()));
	m_sceneTimer->start(interval);

	m_fpsTimer.reset();

	m_fps.fps = 0;
	m_fps.maxFPS = 0;
	m_fps.minFPS = 9999;

	m_currentTime = 0;
	m_lastTime = 0;
}

nulong
NeonWidget::averageFPS() const
{
	return m_fps.avgFPS;
}

nulong
NeonWidget::bestFPS() const
{
	return m_fps.maxFPS;
}

nulong
NeonWidget::currentFPS() const
{
	return m_fps.curFPS;
}

void
NeonWidget::initializeGL()
{
	nuint32 error = glewInit();
	if(error != GLEW_OK) {
		QMessageBox::critical(this, tr("Failed to initialise."),
			tr("Failed to intialise Glew."));
	} else {
		if(!glewIsSupported("GL_VERSION_2_0")) {
			QMessageBox::critical(this, tr("Failed to initialise."), 
				tr("Your current drivers or graphics card does not support OpenGL 2.0 or greater."));
		} else {
			if(!GLEW_ARB_vertex_shader && !GLEW_ARB_fragment_shader) {
				QMessageBox::critical(this, tr("Failed to initialise."),
					tr("Your current drivers or graphics card does not support vertex and fragment shaders."));
			} else {
				if(!GLEW_ARB_transpose_matrix) {
					QMessageBox::critical(this, tr("Failed to initialise."),
						tr("Your current drivers or graphics card does not support transpose matrix."));
				} else {
					initialise();
				}
			}
		}
	}
}

void
NeonWidget::keyPressEvent(QKeyEvent *event)
{
	switch(event->key())
	{
	case Qt::Key_Escape:
		close();
		break;
	}
}

void
NeonWidget::paintGL()
{
	++m_fps.fps;

	m_currentTime = m_fpsTimer.milliseconds();
	scene(m_currentTime);

	if(m_currentTime - m_lastTime > 1000) {
		m_fps.curFPS = static_cast<nuint32>((m_fps.fps / 
			static_cast<nfloat>((m_currentTime - m_lastTime)) * 1000.0));
		m_lastTime = m_currentTime;

		if(m_fps.avgFPS == 0) {
			m_fps.avgFPS = m_fps.curFPS;
		} else {
			m_fps.avgFPS = (m_fps.avgFPS + m_fps.curFPS) / 2;
		}

		m_fps.maxFPS = qMax(m_fps.maxFPS, m_fps.curFPS);

		if(!m_fps.curFPS == 0) {
			m_fps.minFPS = qMin(m_fps.minFPS, m_fps.curFPS);
		}

		m_fps.fps = 0;
	}
}

void
NeonWidget::resizeGL(int w, int h)
{
	resize(w, h);
}

void
NeonWidget::swapInterval(bool on)
{
#ifdef Q_CC_MSVC
	if(WGLEW_EXT_swap_control) {
		wglSwapIntervalEXT(on);
	}
#endif
}

void
NeonWidget::timeOut()
{
	updateGL();
}

void
NeonWidget::timedOut()
{
	timeOut();
}

nulong
NeonWidget::worstFPS() const
{
	return m_fps.minFPS;
}